package com.campus.service.impl;

import com.campus.constant.JwtClaimsConstant;
import com.campus.constant.MessageConstant;
import com.campus.constant.StatusConstant;
import com.campus.context.CurrentHolder;
import com.campus.exception.AccountLockedException;
import com.campus.exception.PasswordErrorException;
import com.campus.exception.AccountNotFoundException;
import com.campus.exception.UsernameDuplicateException;
import com.campus.mapper.UserMapper;
import com.campus.pojo.dto.UserLoginDTO;
import com.campus.pojo.dto.UserPageQueryDTO;
import com.campus.pojo.dto.UserRegisterDTO;
import com.campus.pojo.dto.UserUpdatePwdDTO;
import com.campus.pojo.entity.User;
import com.campus.pojo.vo.UserLoginVO;
import com.campus.pojo.vo.UserVO;
import com.campus.properties.JwtProperties;
import com.campus.result.PageResult;
import com.campus.service.UserService;
import com.campus.utils.JwtUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtProperties jwtProperties;

    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        //1.查询数据库是否有当前用户
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();
        User user = userMapper.getUser(username);

        //2.处理各自异常情况 无用户 用户名或密码不对 账号被锁定
        if (user ==  null) {
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对 将前端传递的密码进行md5加密并与数据库中的密码进行比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        if (!password.equals(user.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (user.getStatus() == StatusConstant.ACCOUNT_DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        //3.登录后下发jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getUserSecretKey(),
                jwtProperties.getUserTtl(),
                claims);
        log.info("jwt令牌：{}", token);

        //4.封装VO对象
        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .name(user.getName())
                .username(user.getUsername())
                .role(user.getRole())
                .token(token)
                .status(user.getStatus())
                .build();

        //4.返回vo对象
        return userLoginVO;

    }

    @Override
    public void register(UserRegisterDTO userRegisterDTO) {
        //1.查询数据库中是否有相同用户名 这里不比对也可以 因为数据库对象的username字段设置了唯一索引 会报错并被全局异常处理器捕获
        String username = userRegisterDTO.getUsername();
        User user = userMapper.getUser(username);
        if (user != null) {
            throw new UsernameDuplicateException(MessageConstant.USERNAME_ALREADY_EXISTS);
        }

        //2.构建entity对象-user
        user = User.builder()
                .name(userRegisterDTO.getName())
                .username(username)
                .password(DigestUtils.md5DigestAsHex(userRegisterDTO.getPassword().getBytes()))
                .role(User.ROLE_USER) //不指定也可以 因为数据库对象的role字段设置了默认值1
                .status(StatusConstant.ACCOUNT_ENABLE)//不指定也可以 因为数据库对象的status字段设置了默认值1
                .build();

        //2.调用mapper方法
        userMapper.insert(user);

    }

    @Override
    public void updatePassword(UserUpdatePwdDTO userUpdatePwdDTO) {
        //1.查询旧密码是否正确
        String oldPassword = userUpdatePwdDTO.getOldPassword();
        oldPassword = DigestUtils.md5DigestAsHex(oldPassword.getBytes());
        //id和username都可以 都是唯一的
        Long userId = CurrentHolder.getCurrentId();
        User user = userMapper.getUserById(userId);

        //2.处理各自异常情况 无用户 旧密码错误
        if (user ==  null) {
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        if (!oldPassword.equals(user.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.OLD_PASSWORD_ERROR);
        }

        //3.修改密码
        String newPassword = DigestUtils.md5DigestAsHex(userUpdatePwdDTO.getNewPassword().getBytes());
        userMapper.updatePassword(userId, newPassword);
    }

    @Override
    public PageResult<UserVO> pageQuery(UserPageQueryDTO userPageQueryDTO) {
        //1.设置分页参数
        PageHelper.startPage(userPageQueryDTO.getCurrentPage(), userPageQueryDTO.getPageSize());

        //2.执行分页查询
        Page<UserVO> page = userMapper.pageQuery(userPageQueryDTO);

        //3.返回结果
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    @Override
    public void updateStatus(Long id, Integer status) {
        userMapper.updateStatus(id, status);
    }

    @Override
    public void resetPassword(Long id) {
        //1.重置密码为123456 经过md5加密更新数据库
        String password = DigestUtils.md5DigestAsHex("123456".getBytes());

        //2.调用mapper
        userMapper.resetPassword(id, password);
    }
}
